import { Expression } from '@babel/types';
import generate from '@babel/generator';
import { IScope } from '../../../../types';
import { parseExpressionConvertThis2Context } from '../../../expressionParser';

const logger: any = () => {};

/**
 * 将所有的 this.xxx 替换为 __$$context.xxx 或直接替换循环变量
 *
 * 注意：在使用箭头函数的情况下，通常不需要转换this引用
 * 只有在特定情况下（如在非箭头函数中使用this）才需要转换
 * 对于循环变量，如this.item和this.index，应直接替换为item和index
 *
 * @param expr 表达式
 * @param scope 作用域
 * @param options 选项
 * @returns 转换后的表达式
 */
export function transformThis2Context(
  expr: string | Expression,
  scope: IScope,
  { ignoreRootScope = false, forceTransform = false, preserveThisForLoopVars = false } = {},
): string {
  // 获取代码字符串
  const codeStr = typeof expr === 'string' ? expr : generate(expr).code;
  logger('【transformThis2Context】开始处理表达式:', codeStr, {
    ignoreRootScope,
    forceTransform,
    preserveThisForLoopVars,
  });

  // 获取当前作用域中的所有绑定变量（包括循环变量）
  const bindings = scope.bindings?.getAllBindings() || [];
  logger('【transformThis2Context】当前作用域变量:', bindings);

  // 如果需要保留循环变量的this引用（用于getStaticExprValue函数），则直接返回原始表达式
  if (preserveThisForLoopVars) {
    logger('【transformThis2Context】需要保留循环变量的this引用，处理JSSlot参数');

    // 处理JSSlot参数，确保添加this.前缀
    let processedCode = codeStr;

    if (bindings.length > 0) {
      logger('【transformThis2Context】开始处理JSSlot参数引用');
      bindings.forEach((binding) => {
        // 检查是否已经有this前缀
        const thisPattern = new RegExp(`\\bthis\\.${binding}\\b`, 'g');
        const standalonePattern = new RegExp(`\\b${binding}\\b(?!\\s*=)(?!\\.|\\\")`, 'g');

        // 如果表达式中有独立的binding变量（没有this前缀），则添加this前缀
        if (standalonePattern.test(processedCode) && !thisPattern.test(processedCode)) {
          logger(`【transformThis2Context】为JSSlot参数 ${binding} 添加this前缀`);
          processedCode = processedCode.replace(standalonePattern, `this.${binding}`);
        }

        // 处理带属性的JSSlot参数，如record.property或record?.property
        const propPattern = new RegExp(`\\b${binding}(\\??\\.\\w+)`, 'g');
        if (propPattern.test(processedCode)) {
          // 检查是否已经有this前缀
          const thisPropPattern = new RegExp(`\\bthis\\.${binding}(\\??\\.\\w+)`, 'g');
          if (!thisPropPattern.test(processedCode)) {
            logger(`【transformThis2Context】为带属性的JSSlot参数 ${binding} 添加this前缀`);
            processedCode = processedCode.replace(propPattern, `this.${binding}$1`);
          }
        }
      });
      logger('【transformThis2Context】处理JSSlot参数后的表达式:', processedCode);
    }

    return processedCode;
  }

  // 处理循环变量引用，将this.item和this.index替换为直接的item和index
  // 注意处理嵌套循环的情况，只替换当前作用域中存在的变量
  let processedCode = codeStr;

  if (bindings.length > 0) {
    logger('【transformThis2Context】开始处理作用域变量引用');
    bindings.forEach((binding) => {
      // 使用正则表达式替换this.binding为直接的binding
      const pattern = new RegExp(`\\bthis\\.${binding}\\b`, 'g');
      if (pattern.test(processedCode)) {
        logger(`【transformThis2Context】替换 this.${binding} 为 ${binding}`);
        processedCode = processedCode.replace(pattern, binding);
      }
    });
    logger('【transformThis2Context】处理作用域变量后的表达式:', processedCode);
  }

  // 默认不转换其他this引用，除非明确要求
  if (!forceTransform) {
    logger('【transformThis2Context】不需要转换其他this引用，返回处理后的表达式');
    return processedCode;
  }

  if (ignoreRootScope && scope.parent == null) {
    logger('【transformThis2Context】忽略根作用域，返回处理后的表达式');
    return processedCode;
  }

  // 对于需要转换的其他this引用，使用parseExpressionConvertThis2Context
  logger('【transformThis2Context】需要转换其他this引用，使用parseExpressionConvertThis2Context');
  const result = parseExpressionConvertThis2Context(processedCode, '__$$context', bindings);
  logger('【transformThis2Context】最终处理结果:', result);
  return result;
}
